package com.zxg.zbc.web.common.module;

import java.io.IOException;
import java.io.StringReader;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import javax.xml.parsers.DocumentBuilderFactory;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.io.SAXReader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.xml.sax.InputSource;

import com.alibaba.citrus.service.requestcontext.parser.ParameterParser;
import com.alibaba.citrus.turbine.Context;
import com.alibaba.citrus.turbine.Navigator;
import com.alibaba.citrus.turbine.dataresolver.Param;
import com.zxg.util.WeixinApiConfigs;
import com.zxg.util.WeixinComponent;
import com.zxg.zbc.web.common.util.SHA1;
import com.zxg.zbc.web.common.util.weixin.AesException;
import com.zxg.zbc.web.common.util.weixin.WXBizMsgCrypt;

import net.sf.ehcache.Cache;

public abstract class BaseWeixinPayResult {

  @Autowired
  protected HttpSession         session;

  @Autowired
  protected HttpServletRequest  request;
  @Autowired
  protected HttpServletResponse response;

  @Autowired
  protected Cache               baseCache;
  protected final static Logger log                    = LoggerFactory.getLogger("WEIXIN");

  DocumentBuilderFactory        documentBuilderFactory = DocumentBuilderFactory.newInstance();

  public void execute(Context context, @Param("signature") String signature, @Param("timestamp") String timestamp, @Param("nonce") String nonce,
      @Param("echostr") String echostr, @Param("encrypt_type") String encrypt_type, @Param("msg_signature") String msg_signature, ParameterParser params,
      Navigator nav) {

    try {

      WeixinComponent currentApp = generateCurrentApp();
      
      boolean isLegal = true;// isLegal(appInfo.getToken(), signature,
                             // timestamp, nonce);

      SAXReader reader = new SAXReader();
      Document postReadData = reader.read(request.getInputStream());
      log.warn("isLegal: " + isLegal + " receive:" + postReadData.asXML());
      if (encrypt_type != null && encrypt_type.equals("aes")) {
        log.warn("need aes decode");
        postReadData = decode(currentApp, postReadData, msg_signature, timestamp, nonce);
      }
      String postWriteDate = doExecute(context, params, nav, postReadData);
      log.warn("will postWritDate:" + postWriteDate);
      if (postWriteDate != null && !postWriteDate.equals("") && postWriteNeedAes(encrypt_type != null && encrypt_type.equals("aes"))) {
        log.warn("need post write aes");
        postWriteDate = encode(currentApp, postWriteDate, msg_signature, timestamp, nonce);
      }

      if (postWriteDate != null && !postWriteDate.equals("")) {
        if (isLegal || skipUnlegal()) {
          try {
            response.getWriter().print(postWriteDate);
          } catch (IOException e) {
            log.error("error ", e);
          }
        }
      }
    } catch (Exception e) {
      log.error("error ", e);
    }

  }

  protected boolean skipUnlegal() {
    return false;
  }

  public boolean isLegal(String token, String signature, String timestamp, String nonce) {
    String[] str = { token, timestamp, nonce };
    Arrays.sort(str);
    String bigStr = str[0] + str[1] + str[2];
    String reSignature = new SHA1().getDigestOfString(bigStr.getBytes()).toLowerCase();
    return reSignature.equalsIgnoreCase(signature);
  }

  private String encode(WeixinComponent currentApp, String postWriteDate, String msg_signature, String timestamp, String nonce) {
    WeixinApiConfigs.ComponentInfo appInfo = WeixinApiConfigs.getAppInfoByApp(currentApp);

    WXBizMsgCrypt pc = getWXMsgCrypt(appInfo);

    try {
      String rtn = pc.encryptMsg(postWriteDate, timestamp, nonce);
      return rtn;
    } catch (AesException e) {
      log.error("aes error ", e);
    }
    return null;
  }

  protected boolean postWriteNeedAes(boolean aes) {
    return aes;
  }

  protected abstract String doExecute(Context context, ParameterParser params, Navigator nav, Document postReadData);

  private WeixinComponent generateCurrentApp() {
    return WeixinComponent.ZXG;
  }

  private Document decode(WeixinComponent app, Document postReadData, String msg_signature, String timestamp, String nonce) {
    WeixinApiConfigs.ComponentInfo appInfo = WeixinApiConfigs.getAppInfoByApp(app);
    try {
      WXBizMsgCrypt pc = getWXMsgCrypt(appInfo);
      String mingwen = pc.decryptMsgAppId(msg_signature, timestamp, nonce, postReadData.asXML());
      log.warn("解密后明文: " + mingwen);

      StringReader sr = new StringReader(mingwen);
      InputSource is = new InputSource(sr);
      SAXReader reader = new SAXReader();
      Document document = reader.read(is);
      return document;
    } catch (AesException e) {
      log.error("aes error ", e);
    } catch (DocumentException e) {
      log.error("aes DocumentException error ", e);
    }

    return null;
  }

  static Map<String, WXBizMsgCrypt> crtpts = new HashMap<String, WXBizMsgCrypt>();

  private static WXBizMsgCrypt getWXMsgCrypt(WeixinApiConfigs.ComponentInfo appInfo) {
    String appId = appInfo.getAppId();
    if (crtpts.containsKey(appId)) {
      return crtpts.get(appId);
    } else {
      try {
        WXBizMsgCrypt rtn = new WXBizMsgCrypt(appInfo.getToken(), appInfo.getAesKey(), appId);
        crtpts.put(appId, rtn);
        return rtn;
      } catch (AesException e) {
        log.error("aes error");
      }
    }
    return null;
  }

}
